home *** CD-ROM | disk | FTP | other *** search
/ Super PC 34 / Super PC 34 (Shareware).iso / spc / UTIL / DJGPP2 / V2 / DJTST200.ZIP / tests / libc / crt0 / teststub.asm < prev   
Encoding:
Assembly Source File  |  1995-04-07  |  20.3 KB  |  827 lines

  1. ;
  2. ; $Id: stub.asm 2.2 1994/10/16 02:07:20 dj Exp $
  3. ; $Log: stub.asm $
  4. ; Revision 2.2  1994/10/16  02:07:20  dj
  5. ; added long suffix to cond jumps out of 8-bit range.
  6. ;
  7. ; Revision 2.1  1994/10/14  16:30:40  dj
  8. ; add cws changes for loading the DPMI server
  9. ; also adds bugfixes
  10. ;
  11. ; Revision 2.0  1994/02/13  19:41:59  dj
  12. ; initial version
  13. ;
  14. ;
  15.  
  16. ;-----------------------------------------------------------------------------
  17. ;  djgpp extender-less stub loader
  18. ;
  19. ;  (C) Copyright 1993,1994 DJ Delorie
  20. ;
  21. ;  Redistribution and use in source and binary forms are permitted
  22. ;  provided that: (1) source distributions retain this entire copyright
  23. ;  notice and comment, (2) distributions including binaries display
  24. ;  the following acknowledgement:  ``This product includes software
  25. ;  developed by DJ Delorie and contributors to the djgpp project''
  26. ;  in the documentation or other materials provided with the distribution
  27. ;  and in all advertising materials mentioning features or use of this
  28. ;  software, and (3) binary distributions include information sufficient
  29. ;  for the binary user to obtain the sources for the binary and utilities
  30. ;  required to built and use it. Neither the name of DJ Delorie nor the
  31. ;  names of djgpp's contributors may be used to endorse or promote
  32. ;  products derived from this software without specific prior written
  33. ;  permission.
  34. ;
  35. ;  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  36. ;  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  37. ;  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  38. ;
  39. ;  Revision history:
  40. ;
  41. ;  93/12/05 DJ Delorie    Initial version v2.00, requires DPMI 0.9
  42. ;  94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization
  43. ;  94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease
  44. ;
  45.    .copyright "The STUB.EXE stub loader is Copyright (C) 1993,1994 DJ Delorie."
  46.    .copyright "All users of programs using this stub are entitled to receive the"
  47.    .copyright "sources for this stub and the utilities required to rebuild and restub"
  48.    .copyright "it.  All persons distributing programs using this stub are required"
  49.    .copyright "to provide these on request or include them with the program."
  50.    .copyright "This only applies to the stub, and not neccessarily the whole program."
  51. ;
  52. ;-----------------------------------------------------------------------------
  53. ;  Interface to 32-bit executable:
  54. ;
  55. ;    cs:eip    according to COFF header
  56. ;    ds        32-bit data segment for COFF program
  57. ;    fs        selector for our data segment (fs:0 is stubinfo)
  58. ;    ss:sp    our stack (ss to be freed)
  59. ;    <others>    All unspecified registers have unspecified values in them.
  60. ;-----------------------------------------------------------------------------
  61. ;  This is the stubinfo structure.  The presence of this structure
  62. ;  indicates that the executable is a djgpp v2.00 executable.
  63. ;  Fields will never be deleted from this structure, only obsoleted.
  64. ;
  65.     .org    0            ; just in case
  66. stubinfo:
  67. stubinfo_magic:                ; char [16]
  68.     .db    "go32stub, v 2.00"    ; version may change, [0..7] won't
  69. stubinfo_size:                ; unsigned long
  70.     .dd    stubinfo_end        ; bytes in structure
  71. stubinfo_minstack:            ; unsigned long
  72.     .dd    0x40000            ; minimum amount of DPMI stack space (256K)
  73. stubinfo_memory_handle:            ; unsigned long
  74.     .dd    0            ; DPMI memory handle
  75. stubinfo_initial_size:            ; unsigned long
  76.     .dd    0            ; size of initial segment
  77. stubinfo_minkeep:            ; unsigned short
  78.     .dw    16384            ; amount of automatic real-mode buffer
  79. stubinfo_ds_selector:            ; unsigned short
  80.     .dw    0            ; our DS selector (used for transfer buffer)
  81. stubinfo_ds_segment:            ; unsigned short
  82.     .dw    0            ; our DS segment (used for simulated calls)
  83. stubinfo_psp_selector:            ; unsigned short
  84.     .dw    0            ; PSP selector
  85. stubinfo_cs_selector:            ; unsigned short
  86.     .dw    0            ; to be freed
  87. stubinfo_env_size:            ; unsigned short
  88.     .dw    0            ; number of bytes of environment
  89. stubinfo_basename:            ; char [8]
  90.     .db    8 .dup 0        ; base name of executable to load (asciiz if < 8)
  91. stubinfo_argv0:                ; char [16]
  92.     .db    16 .dup 0        ; used ONLY by the application (asciiz if < 16)
  93. stubinfo_dpmi_server:            ; char [16]
  94.     .db    "CWSDPMI.EXE\0\0\0\0\0"    ; used by stub to load DPMI server if no DPMI already present
  95.  
  96.     .align    4
  97. stubinfo_end:
  98.  
  99. ;-----------------------------------------------------------------------------
  100. ;  First, set up our memory and stack environment
  101.  
  102.     .start                ; execution begins here
  103.     push    cs
  104.     pop    ds
  105.     mov    [stubinfo_ds_segment], ds
  106.  
  107.     mov    [psp_segment], es    ; save the PSP segment
  108.     cld
  109.  
  110. ;-----------------------------------------------------------------------------
  111. ;  Check that we have DOS 3.00 or later.  (We need this because earlier
  112. ;  versions don't supply argv[0] to us and will scrog registers on dpmi exec).
  113.     mov    ah, 0x30
  114.     int    0x21
  115.     cmp    al, 3
  116.     jae    dos3ok
  117.     mov    dx, msg_bad_dos
  118.     jmpl    error
  119. dos3ok:
  120.     mov    [dos_major], al
  121.  
  122. ;-----------------------------------------------------------------------------
  123. ;  Resize memory in case we need to exec a DPMI server
  124.  
  125. resize_again:
  126.     mov    bx, end_of_memory    ; does not include PSP
  127.     mov    ax, [stubinfo_minkeep]
  128.     cmp    bx, ax            ; is our program big enough to hold it?
  129.     jae    @f1
  130.     mov    bx, ax
  131. @f1:
  132.     mov    [stubinfo_minkeep], bx    ; store for reference
  133.     inc    bh            ; add 256 bytes for PSP
  134.     mov    cx, 0xff04        ; 0xff is for below
  135.     shr    bx, cl            ; bytes to paragraphs
  136.  
  137.     mov    ah, 0x4a        ; ES = PSP segment from above
  138.     int    0x21            ; resize our memory block
  139.     jnc    @f1            ; did it work?
  140.     shl    bx,cl            ; calculate smaller [keep] value
  141.     dec    bh
  142.     mov    [stubinfo_minkeep], bx
  143.     jmp    resize_again        ; and try again
  144. @f1:
  145.  
  146. ;-----------------------------------------------------------------------------
  147. ;  Scan environment for "PATH=" and the stub's full name after environment
  148.  
  149.     mov    es, es:[0x2c]        ; get environment segment
  150.     xor    di, di            ; begin search for NUL/NUL (di = 0)
  151. ;    mov    cx, 0xff04        ; effectively `infinite' loop
  152.     xor     al, al
  153.     .db    0xa9            ; "test ax,...." -- skip 2 bytes
  154. scan_environment:
  155.     repne
  156.     scasb                ; search for NUL
  157.     cmpw    es:[di], 0x4150        ; "PA"
  158.     jne    not_path
  159.     scasw
  160.     cmpw    es:[di], 0x4854        ; "TH"
  161.     jne    not_path
  162.     scasw
  163.     cmpb    es:[di], '='
  164.     jne    not_path
  165.     inc    di            ; Point to PATH contents
  166.     mov    [path_off], di        ; save for later
  167. not_path:
  168.     scasb
  169.     jne    scan_environment    ; no, still environment
  170.     scasw                ; adjust pointer to point to prog name
  171.  
  172. ;-----------------------------------------------------------------------------
  173. ;  Get DPMI information before doing anything 386-specific
  174.  
  175.     push    es
  176.     push    di
  177.     xor    cx, cx            ; flag for load attempt set cx = 0
  178.     jz    @f2            ; We always jump, shorter than jmp
  179. @b1:
  180.     mov    dx, msg_no_dpmi
  181.     jmpl    error
  182. @b2:
  183.     or    cx, cx
  184.     jnz    @b1            ; we already tried load once before
  185.     inc    cx
  186.     call    load_dpmi
  187.     jc    @b1
  188. @f2:
  189.     mov    ax, 0x1687        ; get DPMI entry point
  190.     int    0x2f
  191.     or    ax, ax
  192.     jnz    @b2            ; if 0 then it's there
  193.     and    bl, 1            ; 32 bit capable?
  194.     jz    @b2
  195. @f3:
  196.     mov    [modesw], di        ; store the DPMI entry point
  197.     mov    [modesw+2], es
  198.     mov    [modesw_mem], si
  199.     pop    di
  200.     pop    es
  201.  
  202. ;-----------------------------------------------------------------------------
  203. ;  Set up for the DPMI environment
  204.  
  205.     call    include_umb
  206.     mov    bx, [modesw_mem]
  207.     or    bx, bx
  208.     jz    no_dos_alloc
  209.  
  210.     mov    ah, 0x48        ; allocate memory for the DPMI host
  211.     int    0x21
  212.     jcl    error_no_dos_memory_umb
  213.     mov    es, ax
  214.  
  215. no_dos_alloc:
  216.     call    restore_umb
  217.     mov    ax, 1            ; indicates a 32-bit client
  218.     callf    [modesw]        ; enter protected mode
  219.  
  220.     jcl    error_in_modesw
  221.  
  222. ;-----------------------------------------------------------------------------
  223. ; We're in protected mode at this point.
  224.  
  225.     mov    ax, 0x4c00
  226.     int    0x21
  227.  
  228.     mov    [stubinfo_psp_selector], es
  229.     mov    [stubinfo_cs_selector], cs
  230.     mov    ax, ds
  231.     mov    [stubinfo_ds_selector], ax
  232.     mov    es, ax
  233.  
  234.     xor    ax, ax            ; AX = 0x0000
  235.     mov    cx, 1
  236.     int    0x31            ; allocate LDT descriptor
  237.     jc    @f2
  238.     mov    [client_cs], ax
  239.  
  240.     xor    ax, ax            ; AX = 0x0000
  241. ;    mov    cx, 1            ; already set above
  242.     int    0x31            ; allocate LDT descriptor
  243. @f2:
  244.     jcl    perror_no_selectors
  245.     mov    [client_ds], ax
  246.  
  247.     mov    ax, 0x0501
  248.     mov    bx, stubinfo_initial_size[2]
  249.     mov    cx, stubinfo_initial_size[0]
  250.     int    0x31            ; allocate memory block
  251.     jcl    perror_no_dpmi_memory
  252.     mov    client_memory[2], bx
  253.     mov    client_memory[0], cx
  254.     mov    stubinfo_memory_handle[2], si
  255.     mov    stubinfo_memory_handle[0], di
  256.  
  257.     mov    ax, 0x0007
  258.     mov    bx, [client_cs]        ; initialize client CS
  259.     mov    cx, client_memory[2]
  260.     mov    dx, client_memory[0]
  261.     int    0x31            ; set segment base address
  262.  
  263.     mov    ax, 0x0009
  264. ;    mov    bx, [client_cs]        ; already set above
  265.     mov    cx, cs            ; get CPL
  266.     and    cx, 0x0003
  267.     shl    cx, 5
  268.     push    cx            ; save shifted CPL for below
  269.     or    cx, 0xc09b        ; 32-bit, big, code, non-conforming, readable
  270.     int    0x31            ; set descriptor access rights
  271.  
  272.     mov    ax, 0x0008
  273. ;    mov    bx, [client_cs]        ; already set above
  274.     mov    cx, stubinfo_initial_size[2]
  275.     dec    cx
  276.     mov    dx, 0xffff
  277.     int    0x31            ; set segment limit
  278.  
  279.     mov    ax, 0x0007
  280.     mov    bx, [client_ds]        ; initialize client DS
  281.     mov    cx, client_memory[2]
  282.     mov    dx, client_memory[0]
  283.     int    0x31            ; set segment base address
  284.  
  285.     mov    ax, 0x0009
  286. ;    mov    bx, [client_ds]        ; already set above
  287.     pop    cx            ; shifted CPL from above
  288.     or    cx, 0xc093        ; 32-bit, big, data, r/w, expand-up
  289.     int    0x31            ; set descriptor access rights
  290.  
  291.     mov    ax, 0x0008
  292. ;    mov    bx, [client_ds]        ; already set above
  293.     mov    cx, stubinfo_initial_size[2]
  294.     dec    cx
  295.     mov    dx, 0xffff
  296.     int    0x31            ; set segment limit
  297.  
  298. ;-----------------------------------------------------------------------------
  299. ;  Load the program data
  300.  
  301.     mov    ax, 0x0100
  302.     mov    bx, 0x0f00        ; 60K DOS block size
  303.     int    0x31            ; allocate DOS memory
  304.     jnc    @f1
  305.     cmp    ax, 0x0008
  306.     jnel    perror_no_dos_memory
  307.     mov    ax, 0x0100        ; try again with new value in bx
  308.     int    0x31            ; allocate DOS memory
  309.     jcl    perror_no_dos_memory
  310. @f1:
  311.     mov    [dos_block_seg], ax
  312.     mov    [dos_block_sel], dx
  313.     shl    bx, 4            ; paragraphs to bytes
  314.     mov    [dos_block_size], bx
  315.  
  316.     mov    esi, [text_foffset]    ; load text section
  317.     mov    edi, [text_soffset]
  318.     mov    ecx, [text_size]
  319.     call    read_section
  320.  
  321.     mov    esi, [data_foffset]    ; load data section
  322.     mov    edi, [data_soffset]
  323.     mov    ecx, [data_size]
  324.     call    read_section
  325.  
  326.     mov    ax, 0x0101
  327.     mov    dx, [dos_block_sel]
  328.     int    0x31            ; free up the DOS memory
  329.  
  330.     push    ds
  331.     pop    fs
  332.     mov    ds, [client_ds]
  333.     .opsize
  334.     jmpf    fs:[start_eip]        ; start program
  335.  
  336. ;-----------------------------------------------------------------------------
  337. ;  Read a section from the program file
  338.  
  339. read_section:
  340.     mov    eax, esi        ; sector alignment by default
  341.     and    eax, 0x1ff
  342.     add    ecx, eax
  343.     and    si, 0xfe00        ; page align
  344.     and    di, 0xfe00
  345.  
  346.     mov    [read_size], ecx    ; store for later reference
  347.     mov    [read_soffset], edi
  348.  
  349.     call    zero_regs
  350.     mov    dpmi_regs[dr_dx], si    ; store file offset
  351.     shr    esi, 16
  352.     mov    dpmi_regs[dr_cx], si
  353.     mov    bx, [program_file]
  354.     mov    dpmi_regs[dr_bx], bx
  355.     movw    dpmi_regs[dr_ax], 0x4200
  356.     call    pm_dos            ; seek to start of data
  357.  
  358. read_loop:
  359.     call    zero_regs
  360.     movb    dpmi_regs[dr_ah], 0x3f
  361.     mov    bx, [program_file]
  362.     mov    dpmi_regs[dr_bx], bx    ; handle
  363.     mov    ax, [dos_block_seg]
  364.     mov    dpmi_regs[dr_ds], ax
  365.     mov    ax, read_size[2]    ; see how many bytes to read
  366.     or    ax, ax
  367.     jnz    read_too_big
  368.     mov    ax, read_size[0]
  369.     cmp    ax, [dos_block_size]
  370.     jna    read_size_in_ax        ; jna shorter than jmp
  371. read_too_big:
  372.     mov    ax, [dos_block_size]
  373. read_size_in_ax:
  374.     mov    dpmi_regs[dr_cx], ax
  375.     call    pm_dos            ; read the next chunk of file data
  376.  
  377.     xor    ecx, ecx
  378.     mov    cx, dpmi_regs[dr_ax]    ; get byte count
  379.     mov    edi, [read_soffset]    ; adjust pointers
  380.     add    [read_soffset], ecx
  381.     sub    [read_size], ecx
  382.  
  383.     xor    esi, esi        ; esi=0 offset for copy data
  384.     shr    cx, 2            ; ecx < 64K
  385.     push    ds
  386.     push    es
  387.     mov    es, [client_ds]
  388.     mov    ds, [dos_block_sel]
  389.     .addrsize
  390.     rep
  391.     movsd
  392.     pop    es
  393.     pop    ds
  394.  
  395.     add    ecx, [read_size]    ; ecx zero from the rep movsd
  396.     jnz    read_loop
  397.  
  398.     ret
  399.  
  400. ;-----------------------------------------------------------------------------
  401. ;  Routine to check al for delimiter
  402.  
  403. test_delim:
  404.     cmp    al, ':'            ; watch for file name part
  405.     je    @f3
  406.     cmp    al, '/'
  407.     je    @f3
  408.     cmp    al, '\\'
  409. @f3:
  410.     ret
  411.  
  412. ;-----------------------------------------------------------------------------
  413. ;  Copy string from environment to loadname.
  414. ;   On entry: di = environment offset
  415. ;             ah = termination character (null also does)
  416. ;   On exit:  bx = pointer to one character after last observed file delimiter
  417. ;             di = pointer to one character after last copied
  418. ;             si = pointer to the copied termination character
  419. ;             al = terminating character
  420.  
  421. store_env_string:
  422.     mov    si, loadname        ; pointer to buffer
  423.     mov    bx, si            ; in case no delimiters
  424. @b1:
  425.     mov    al, es:[di]        ; copy a character to buffer
  426.     inc    di
  427.     mov    [si], al
  428.     cmp    al, ah            ; end of file name?
  429.     je    @f1
  430.     or    al, al            ; end of file name?
  431.     je    @f1
  432.     inc    si
  433.     call    test_delim
  434.     jne    @b1
  435.     mov    bx, si            ; remember pointer to first char of
  436.     je    @b1            ; next name component (shorter than jmp)
  437. @f1:
  438.     ret
  439.  
  440. ;-----------------------------------------------------------------------------
  441. ;  Most errors come here, early ones jump direct (8088 instructions)
  442.  
  443. error_no_progfile:
  444.     mov    dx, msg_no_progfile
  445.     jmp    error_fn
  446.  
  447. error_not_exe:
  448.     mov    dx, msg_not_exe
  449.     jmp    error_fn
  450.  
  451. error_not_coff:
  452.     mov    dx, msg_not_coff
  453. ;    jmp    error_fn
  454.  
  455. error_fn:
  456.     push    dx
  457.     mov    bx, [loadname_nul]    ; error, print file name
  458.     movb    [bx], '$'
  459.     mov    bx, loadname
  460.     jmp    @f1
  461.  
  462. error_no_dos_memory_umb:
  463.     call    restore_umb
  464. error_no_dos_memory:
  465.     mov    dx, msg_no_dos_memory
  466.     jmp    error
  467.  
  468. error_in_modesw:
  469.     mov    dx, msg_error_in_modesw
  470.     jmp    error
  471.  
  472. perror_no_selectors:
  473.     mov    dx, msg_no_selectors
  474.     jmp    error
  475.  
  476. perror_no_dpmi_memory:
  477.     mov    dx, msg_no_dpmi_memory
  478.     jmp    error
  479.  
  480. perror_no_dos_memory:
  481.     mov    dx, msg_no_dos_memory
  482. ;    jmp    error
  483.  
  484. error:
  485.     push    dx
  486.     mov    bx, err_string
  487. @f1:
  488.     call    printstr
  489.     pop    bx
  490.     call    printstr
  491. exit:
  492.     mov    bx, crlfdollar
  493.     call    printstr
  494.     mov    ax, 0x4cff        ; error exit
  495.     int    0x21
  496.  
  497. printstr1:
  498.     inc    bx
  499.     mov    ah, 2
  500.     int    0x21
  501. printstr:
  502.     mov    dl, [bx]
  503.     cmp    dl, '$'
  504.     jne    printstr1
  505.     ret
  506.  
  507. crlfdollar:
  508.     .db    13,10,'$'
  509. ;-----------------------------------------------------------------------------
  510. ;  DPMI utility functions
  511.  
  512. zero_regs:
  513.     push    ax
  514.     push    cx
  515.     push    di
  516.     xor    ax, ax
  517.     mov    di, dpmi_regs
  518.     mov    cx, 0x19
  519.     rep
  520.     stosw
  521.     pop    di
  522.     pop    cx
  523.     pop    ax
  524.     ret
  525.  
  526. pm_dos:
  527.     mov    ax, 0x0300        ; simulate interrupt
  528.     mov    bx, 0x0021        ; int 21, no flags
  529.     xor     cx, cx            ; cx = 0x0000 (copy no args)
  530.     mov    edi, dpmi_regs
  531.     int    0x31
  532.     ret
  533.  
  534. ;-----------------------------------------------------------------------------
  535. ;  load DPMI server if not present
  536. ;   First check directory from which stub is loaded, then path, then default
  537. ;   On entry di points to image name
  538.  
  539. path_off:
  540.     .dw    0            ; If stays zero, no path
  541.  
  542. load_dpmi:
  543.     xor    ah, ah            ; Copy until this character (=0)
  544.     call    store_env_string    ; copy stub image to "loadname"
  545.     mov    si, bx            ; remove name so we can add DPMI name
  546.     mov    di, [path_off]        ; Pointer to path contents (next try)
  547.     jmp    @f2
  548. loadloop:
  549.     mov    ah, ';'            ; Copy until this character
  550.     call    store_env_string    ; to "loadname"
  551.     cmp    si, loadname        ; anything there?
  552.     je    do_exec            ; final try (no path) let it return
  553.     mov    al, [si-1]
  554.     call    test_delim        ; is final character a path delimiter
  555.     je    @f2
  556.     movb    [si], '\\'        ; no, add separator between path & name
  557.     inc    si
  558. @f2:
  559.     call    do_exec            ; copy our name to string and try load
  560.     jc    loadloop
  561.     ret
  562.  
  563. ;-----------------------------------------------------------------------------
  564. ; add the string CWSDPMI to path ending
  565.  
  566. do_exec:
  567.     call    include_umb
  568.     mov    bx, stubinfo_dpmi_server
  569. @b1:
  570.     mov    al, [bx]
  571.     mov    [si], al
  572.     inc    bx
  573.     inc    si
  574.     or    al, al
  575.     jne    @b1
  576. ;    movw    [si], 0x0a0d        ;debug
  577. ;    movb    [si+2], '$'        ;debug
  578.  
  579.     push    es            ; Save in case of failure
  580.     push    di
  581.  
  582. ;memory saving - use dpmi_regs as a temporary parameter block
  583.     push    ds
  584.     pop    es            ;zero_regs needs es set
  585.     call    zero_regs
  586.     mov    bx, dpmi_regs
  587.     mov    [bx+4], ds        ;segment of command tail
  588.     mov    [bx+2], bx        ;offset (point to zero)
  589.  
  590.     mov    dx, loadname
  591. ;    mov    ah, 9            ;debug
  592. ;    int    0x21            ;debug
  593.     mov    ax, 0x4b00        ;Do program exec
  594.     int    0x21
  595.     pop    di
  596.     pop    es
  597.     jc    @f1            ;carry set if exec failed
  598.  
  599.     mov    ah, 0x4d        ;get return code
  600.     int    0x21
  601.     sub    ax, 0x300        ;ah=3 TSR, al=code (success)
  602.     neg    ax            ;CY, if not originally 0x300
  603. @f1:
  604.     jmp    restore_umb        ;called func. return for us.
  605.  
  606. ;-----------------------------------------------------------------------------
  607. ; Make upper memory allocatable.  Clobbers Ax and Bx.
  608.  
  609. include_umb:
  610.     cmpb    [dos_major], 5        ; Won't work before dos 5
  611.     jb    @f1
  612.     mov    ax, 0x5800        ; get allocation strategy
  613.     int    0x21
  614.     mov    [old_strategy],al
  615.     mov    ax, 0x5802        ; Get UMB status.
  616.     int    0x21
  617.     mov    [old_umb],al
  618.     mov    ax, 0x5801
  619.     mov    bx, 0x0080        ; first fit, first high then low
  620.     int    0x21
  621.     mov    ax, 0x5803
  622.     mov    bx, 0x0001        ; include UMB in memory chain
  623.     int    0x21
  624. @f1:
  625.     ret
  626.  
  627. ; Restore upper memory status.  All registers and flags preserved.
  628.  
  629. restore_umb:
  630.     pushf
  631.     cmpb    [dos_major], 5        ; Won't work before dos 5
  632.     jb    @f1
  633.     push    ax
  634.     push    bx
  635.     mov    ax, 0x5803        ; restore UMB status.
  636.     mov    bl,[old_umb]
  637.     xor    bh, bh
  638.     int    0x21
  639.     mov    ax, 0x5801        ; restore allocation strategy
  640.     mov    bl,[old_strategy]
  641.     xor    bh, bh
  642.     int    0x21
  643.     pop    bx
  644.     pop    ax
  645. @f1:
  646.     popf
  647.     ret
  648.  
  649. ;-----------------------------------------------------------------------------
  650. ;  Stored Data
  651. err_string:
  652.     .db    "Load error: $"
  653. msg_no_progfile:
  654.     .db    ": cannot open$"
  655. msg_not_exe:
  656.     .db    ": not an EXE file$"
  657. msg_not_coff:
  658.     .db    ": not a COFF file$"
  659. msg_no_dpmi:
  660.     .db    "no DPMI$"
  661. msg_no_dos_memory:
  662.     .db    "no DOS memory$"
  663. msg_bad_dos:
  664.     .db    "need DOS 3$"
  665. msg_error_in_modesw:
  666.     .db    "can't switch mode$"
  667. msg_no_selectors:
  668.     .db    "no DPMI selectors$"
  669. msg_no_dpmi_memory:
  670.     .db    "no DPMI memory$"
  671.  
  672. ;-----------------------------------------------------------------------------
  673. ;  Unstored Data, available during and after mode switch
  674.  
  675. last_generated_byte:
  676.  
  677.     .align    512            ; Align ourselves to a sector
  678.                     ;  boundary for startup speed.
  679.     .bss                ; data after this isn't in file.
  680.  
  681. modesw:                    ; address of DPMI mode switch
  682.     .dd    0
  683. modesw_mem:                ; amount of memory DPMI needs
  684.     .dw    0
  685.  
  686. program_file:                ; file ID of program data
  687.     .dw    0
  688.  
  689. text_foffset:                ; offset in file
  690.     .dd    0
  691. text_soffset:                ; offset in segment
  692.     .dd    0
  693. text_size:                ; bytes to load
  694.     .dd    0
  695.  
  696. data_foffset:                ; offset in file
  697.     .dd    0
  698. data_soffset:                ; offset in segment
  699.     .dd    0
  700. data_size:                ; bytes to load
  701.     .dd    0
  702.  
  703. start_eip:                ; EIP value to start at
  704.     .dd    0
  705. client_cs:                ; must follow start_eip
  706.     .dw    0
  707. client_ds:
  708.     .dw    0
  709.  
  710. client_memory:
  711.     .dd    0
  712.  
  713. dos_block_seg:
  714.     .dw    0
  715. dos_block_sel:
  716.     .dw    0
  717. dos_block_size:
  718.     .dw    0
  719.  
  720. read_soffset:
  721.     .dd    0
  722. read_size:
  723.     .dd    0
  724.  
  725. dpmi_regs:
  726.     .db    0x32 .dup 0
  727. dr_edi = 0x00
  728. dr_di  = 0x00
  729. dr_esi = 0x04
  730. dr_si  = 0x04
  731. dr_ebp = 0x08
  732. dr_bp  = 0x08
  733. dr_ebx = 0x10
  734. dr_bx  = 0x10
  735. dr_bl  = 0x10
  736. dr_bh  = 0x11
  737. dr_edx = 0x14
  738. dr_dx  = 0x14
  739. dr_dl  = 0x14
  740. dr_dh  = 0x15
  741. dr_ecx = 0x18
  742. dr_cx  = 0x18
  743. dr_cl  = 0x18
  744. dr_ch  = 0x19
  745. dr_eax = 0x1c
  746. dr_ax  = 0x1c
  747. dr_al  = 0x1c
  748. dr_ah  = 0x1d
  749. dr_efl = 0x20
  750. dr_es  = 0x22
  751. dr_ds  = 0x24
  752. dr_fs  = 0x26
  753. dr_gs  = 0x28
  754. dr_ip  = 0x2a
  755. dr_cs  = 0x2c
  756. dr_sp  = 0x2e
  757. dr_ss  = 0x30
  758.  
  759. ;-----------------------------------------------------------------------------
  760.  
  761.     .align    16            ; so that stack ends on para boundary
  762.     .dw    128 .dup 0
  763.     .stack
  764.  
  765. ;end_of_memory:                ; data after this isn't used in prot mode
  766.  
  767. ;-----------------------------------------------------------------------------
  768. ;  Real-Mode Only Data, not available during or after mode switch
  769.  
  770. psp_segment:
  771.     .dw    0
  772.  
  773. loadname_nul:                ; offset of NUL so it can become '$'
  774.     .dw    0
  775. loadname:                ; name of program file to load, if it
  776.     .db    81 .dup 0        ; gets really long ok to overwrite next
  777.  
  778. exe_header:                ; loaded from front of loadfile
  779. exe_magic:
  780.     .dw    0
  781. exe_bytes_last_page:
  782.     .dw    0
  783. exe_sectors:
  784.     .dw    0
  785. exe_header_length = . - exe_header
  786.  
  787. coff_offset:
  788.     .dd    0            ; from start of file
  789.  
  790. coff_header:                ; loaded from after stub
  791.     .db    20 .dup 0
  792. aout_header:
  793.     .db    28 .dup 0
  794. text_section:
  795.     .db    40 .dup 0
  796. data_section:
  797.     .db    40 .dup 0
  798. bss_section:
  799.     .db    40 .dup 0
  800. coff_header_length = . - coff_header
  801.  
  802. old_strategy:
  803.     .db    0
  804. old_umb:
  805.     .db    0
  806.  
  807. dos_major:
  808.     .db    0
  809.  
  810.     .align    16            ; Align ourselves to a paragraph
  811. end_of_memory:                ; resize is done early so must keep all
  812.  
  813. ;-----------------------------------------------------------------------------
  814. ;  structure definitions
  815. ;
  816.  
  817. coff_magic    = 0            ; from coff header
  818.  
  819. aout_entry    = 16            ; from aout header
  820.  
  821. s_paddr        = 8            ; from section headers
  822. s_vaddr        = 12
  823. s_size        = 16
  824. s_scnptr    = 20
  825.  
  826.  
  827.